package com.broadsoft.platform.wfengine.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broadsoft.platform.wfengine.ApplicationType;
import com.broadsoft.platform.wfengine.NodeType;
import com.broadsoft.platform.wfengine.WorkflowType;
import com.broadsoft.platform.wfengine.helper.UnmarshalHelper;


/**
 * 
* FIXME: <A few lines of description of what class is about and what it does.> 
*
* <HR/><B>Modification Block</B>
* <P>
* Version: FIXME: 1.0.1 <BR>
* Author: FIXME: luzhen
* Date: 2011-9-15
* TAG: <A short name to find out all changed made by this modification.>
* Comments: Created.
* Bug fix NO.: <If required>
* </P>
* <P>
* ... Other Modifications following above structure.
* </P>
*
 */
public class ParsedWorkflowDefinition {

    private final static Logger logger = LoggerFactory.getLogger(ParsedWorkflowDefinition.class);
    private static Map<String,WorkflowType> mapOfAllAppFlow=new HashMap<String,WorkflowType>();//flowname,WorkflowType
    private static Map<String,Map<String,NodeType>> mapOfAllAppNode=new HashMap<String,Map<String,NodeType>>();//flowname,nodename,NodeType

    private static Map<String,Map<String,List<NodeType>>> mapOfSourceNodeType=new HashMap<String,Map<String,List<NodeType>>>();//flowName,destNodeName,source node list
    
    private String appFileName;
    
    public ApplicationType getApplicationType(String appFileName){  
        ApplicationType applicationType=null;
        try {
            applicationType = UnmarshalHelper.unmarshal(appFileName);
        } catch (JAXBException e) { 
            e.printStackTrace();
        }
        return applicationType;
    } 
    
    
    public void init(){ 
        ApplicationType applicationType=getApplicationType(appFileName);
        List<WorkflowType> listOfWorkflowType = applicationType.getWorkflow();
        for (WorkflowType workflowType : listOfWorkflowType) {
            String flowName=workflowType.getName();
            if(logger.isTraceEnabled()){
                logger.trace("The flowName is {}",flowName);
            }
            mapOfAllAppFlow.put(flowName, workflowType);
            List<NodeType> listOfNodeType = workflowType.getNodeOrExternalNodeOrTask();
            Map<String,NodeType> nodeMapOnFlow=new HashMap<String,NodeType>();
            Map<String,List<NodeType>> sourceNodeMapOnFlow=new HashMap<String,List<NodeType>>();
            for(NodeType nodeType:listOfNodeType){ 
                String nodeName=nodeType.getName(); 
                if(logger.isTraceEnabled()){
                    logger.trace("The nodeName is {}",nodeName);
                    logger.trace("The nodeType is {}",nodeType);
                }
                nodeMapOnFlow.put(nodeName, nodeType); 
                //  
                List<String> listOfDestNodeName=nodeType.getDestNode();
                for(String destNodeName:listOfDestNodeName){
                    if(null!=sourceNodeMapOnFlow.get(destNodeName)){
                        sourceNodeMapOnFlow.get(destNodeName).add(nodeType); 
                    }else{// initialize the array list
                        List<NodeType> listSourceNodeType=new ArrayList<NodeType>();
                        listSourceNodeType.add(nodeType);
                        sourceNodeMapOnFlow.put(destNodeName, listSourceNodeType);  
                    }
                } 
              
            }//end of for
            
            //end node
            NodeType endNodeType= workflowType.getEndNode();
            nodeMapOnFlow.put(endNodeType.getName(), endNodeType); 
            //end node
            NodeType startNodeType= workflowType.getStartNode();
            nodeMapOnFlow.put(startNodeType.getName(), startNodeType); 
            mapOfAllAppNode.put(flowName, nodeMapOnFlow);
            //source
            String destOnStartNodeName=startNodeType.getName();
            List<NodeType> listSourceNodeType=new ArrayList<NodeType>();
            listSourceNodeType.add(startNodeType);
            sourceNodeMapOnFlow.put(destOnStartNodeName, listSourceNodeType); 
            mapOfSourceNodeType.put(flowName, sourceNodeMapOnFlow);
        } 
        printDebugInfo();
        printDebugInfo2();
    }//end of init
    
   
    
    private void printDebugInfo(){
        logger.trace("---------Debug Information----begin----");
        //appNodeMap
        Set<String> keySetOnFlow=mapOfAllAppNode.keySet();
        Iterator<String> keyIteratorOnFlow=keySetOnFlow.iterator();
        while(keyIteratorOnFlow.hasNext()){
            String keyOnFlow=keyIteratorOnFlow.next();
            logger.trace("---------The following information is showing the nodes for the workflow[{}]----begin----",keyOnFlow);
            Map<String,NodeType> mapOfNode=mapOfAllAppNode.get(keyOnFlow);
            Set<String> keySetOnNode=mapOfNode.keySet();
            Iterator<String> keyIteratorOnNode=keySetOnNode.iterator();
            while(keyIteratorOnNode.hasNext()){
                String keyOnNode=keyIteratorOnNode.next();
                NodeType nodeType=mapOfNode.get(keyOnNode);
                logger.trace("Node name is {} and the NodeType is {}",keyOnNode,nodeType);
            }
        }//end of while
        //mapOfSourceNodeType
        logger.trace("---------Debug Information----end----");
       
        
        
        
    }
    
    private void printDebugInfo2(){
        logger.trace("---------Debug2 Information----begin----");
        //appNodeMap
        Set<String> keySetOnFlow=mapOfSourceNodeType.keySet();
        Iterator<String> keyIteratorOnFlow=keySetOnFlow.iterator();
        while(keyIteratorOnFlow.hasNext()){
            String keyOnFlow=keyIteratorOnFlow.next();
            logger.trace("---------The following information is showing the nodes for the workflow[{}]--------",keyOnFlow);
            Map<String,List<NodeType>> mapOfNode=mapOfSourceNodeType.get(keyOnFlow);
            Set<String> keySetOnNode=mapOfNode.keySet();
            Iterator<String> keyIteratorOnNode=keySetOnNode.iterator();
            while(keyIteratorOnNode.hasNext()){
                String keyOnNode=keyIteratorOnNode.next();
                List<NodeType> listOfNodeType=mapOfNode.get(keyOnNode);
                for(NodeType nodeType:listOfNodeType){
                    logger.trace("Node name is {} and the Source NodeType is {}",keyOnNode,nodeType); 
                }
            }
        }//end of while
        //mapOfSourceNodeType
        logger.trace("---------Debug2 Information----end----"); 
        
        
    }

    public String getAppFileName() {
        return appFileName;
    }

    public void setAppFileName(String appFileName) {
        this.appFileName = appFileName;
    }

 

 
    
    public NodeType getNodeTypeByName(String flowName,String nodeName){
        if(logger.isTraceEnabled()){
            logger.trace("The flowName is {}",flowName);
            logger.trace("The nodeName is {}",nodeName);
        }
        NodeType nodeType=mapOfAllAppNode.get(flowName).get(nodeName);
        return nodeType;
    }
    
    public List<NodeType> getAllSourceNodeByDestNodeName(String flowName,String destNodeName){
        if(logger.isTraceEnabled()){
            logger.trace("The flowName is {}",flowName);
            logger.trace("The destNodeName is {}",destNodeName);
        }
        List<NodeType>  listOfNodeType= mapOfSourceNodeType.get(flowName).get(destNodeName); 
        return listOfNodeType;
        
    }
    
    
    public WorkflowType getWorkflowTypeByName(String flowName){
        WorkflowType workflowType=mapOfAllAppFlow.get(flowName);
        return workflowType;
    }
    
    
    
    
    
    
    
}
